#include <linux/types.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/delay.h>
#include <mach/io.h>
#include <linux/io.h>
#include <mach/fh_predefined.h>
#include "chip.h"
#include "soc.h"

static DEFINE_SPINLOCK(scu_lock);
static unsigned long flag;

static inline void fh_set_scu_en(void)
{
	spin_lock_irqsave(&scu_lock, flag);
	writel(0x706c6c63, (void __iomem *)VA_SYS_REG_BASE
		+ REG_PMU_SCU_PLL_WREN);
	writel(0x706c6c63, (void __iomem *)VA_SYS_REG_BASE
		+ REG_PMU_DDR_SCU_WREN);
}

static inline void fh_set_scu_di(void)
{
	writel(0x0, (void __iomem *)VA_SYS_REG_BASE
		+ REG_PMU_SCU_PLL_WREN);
	writel(0x0, (void __iomem *)VA_SYS_REG_BASE
		+ REG_PMU_DDR_SCU_WREN);
	spin_unlock_irqrestore(&scu_lock, flag);
}


void fh_pmu_set_reg(unsigned int offset, unsigned int data)
{
	fh_set_scu_en();
	writel(data, (void __iomem	*)VA_SYS_REG_BASE + offset);
	fh_set_scu_di();
}
EXPORT_SYMBOL(fh_pmu_set_reg);

unsigned int fh_pmu_get_reg(unsigned int offset)
{
	return readl((void __iomem	*)VA_SYS_REG_BASE + offset);
}
EXPORT_SYMBOL(fh_pmu_get_reg);

void fh_pmu_set_reg_m(unsigned int offset, unsigned int data, unsigned int mask)
{
	fh_set_scu_en();
	writel((((readl((void __iomem *)VA_SYS_REG_BASE + offset)) &
			(~(mask))) | ((data) & (mask))),
		(void __iomem *)VA_SYS_REG_BASE + offset);
	fh_set_scu_di();

}
EXPORT_SYMBOL(fh_pmu_set_reg_m);

unsigned long long fh_get_pts64(void)
{
	unsigned int high, low;
	unsigned long long pts64;

	fh_pmu_set_reg(REG_PMU_PTSLO, 0x01);
	high = fh_pmu_get_reg(REG_PMU_PTSHI);
	low = fh_pmu_get_reg(REG_PMU_PTSLO);
	pts64 = (((unsigned long long)high) << 32) | ((unsigned long long)low);

	return pts64;
}
EXPORT_SYMBOL(fh_get_pts64);

void fh_get_chipid(unsigned int *plat_id, unsigned int *chip_id)
{
	unsigned int _plat_id = 0;

	_plat_id = fh_pmu_get_reg(REG_PMU_CHIP_ID);
	if (plat_id != NULL)
		*plat_id = _plat_id;

	if (chip_id != NULL)
		*chip_id = fh_pmu_get_reg(REG_PMU_IP_VER);
}
EXPORT_SYMBOL(fh_get_chipid);

unsigned int fh_pmu_get_ddrsize(void)
{
	return fh_pmu_get_reg(REG_PMU_DDR_SIZE);
}
EXPORT_SYMBOL_GPL(fh_pmu_get_ddrsize);

#if 0
void fh_pmu_perfmon_init(int timelow, int timehigh)
{
	#if 0
	int dmc_apb_base = SYS_REG_P2V(DMC_SYS_APB_REG_BASE);

	/* enable perfmon0~5 clk, busmon timer clk */
	SET_REG_M(dmc_apb_base+DMC_CLK_CTRL, (0x001000fe), (0x001000fe));
	SET_REG_M(dmc_apb_base+DFIMON_TMR1_CTRL0, (0x3), (0x3));
	SET_REG_M(dmc_apb_base+DFIMON_TMR1_CTRL0, (0x1), (0x3));

	//high time
	SET_REG(dmc_apb_base+HIGH_LEN_TIMER1, timehigh);
	//low time
	SET_REG(dmc_apb_base+LOW_LEN_TIMER1, timelow);
	/* perf_trigger_sel */
	SET_REG_M(dmc_apb_base+PERF_TRIGGER, 0x2, 0x2);
	#endif
}
EXPORT_SYMBOL(fh_pmu_perfmon_init);

void fh_pmu_perfmon_timer_cnt_clr(void)
{
	#if 0
	int dmc_apb_base = SYS_REG_P2V(DMC_SYS_APB_REG_BASE);

	SET_REG_M(dmc_apb_base+DFIMON_TMR1_CTRL0, 0x0, 0x3);
	SET_REG_M(dmc_apb_base+DFIMON_TMR1_CTRL0, 0x1, 0x3);
	#endif
}
EXPORT_SYMBOL(fh_pmu_perfmon_timer_cnt_clr);

void fh_pmu_perfmon_rd_trigger(void)
{
	#if 0
	int dmc_apb_base = SYS_REG_P2V(DMC_SYS_APB_REG_BASE);

	/* perf_rd_trigger */
	SET_REG_M(dmc_apb_base+PERF_TRIGGER, 0x1, 0x1);
	#endif
}
EXPORT_SYMBOL(fh_pmu_perfmon_rd_trigger);

void fh_pmu_set_mclk(int freq)
{
	#if 0
	int base = SYS_REG_P2V(TOP_SYS_APB_REG_BASE);

	SET_REG(base+IIS0_CLK_CTRL, 0);
	SET_REG(base+CKG_I2S_FRAC_DIV_N, I2S_CLK_FREQ/1600);
	SET_REG(base+CKG_I2S_FRAC_DIV_M, freq/800);

	SET_REG(base+IIS0_CLK_CTRL, CKG_I2S_FRAC_DIV_EN|CKG_I2S_FAST_EN);
	#endif
}
EXPORT_SYMBOL(fh_pmu_set_mclk);

static void _reset_ip(int base, int offset, int bit)
{
	#if 0
	int vbase = SYS_REG_P2V(base);

	SET_REG_M(vbase+offset, BIT(bit), BIT(bit));
	udelay(1);
	SET_REG_M(vbase+offset, 0, BIT(bit));
	#endif
}

static void _reset_ip_wc(int base, int offset, int bit)
{
	#if 0
	int vbase = SYS_REG_P2V(base);

	SET_REG_M(vbase+offset, BIT(bit), BIT(bit));
	while (GET_REG(vbase+offset) & BIT(bit))
		;
	#endif
}

void fh_pmu_reset_i2s(void)
{
	#if 0
	_reset_ip(TOP_SYS_APB_REG_BASE, AP_PERI_SOFT_RST0, I2S0_SOFT_RST);
	#endif
}
EXPORT_SYMBOL(fh_pmu_reset_i2s);

void fh_pmu_set_emmc_clock(unsigned int clock)
{
	#if 0
	static unsigned int emmc_clk[] =
	{
		24000000, 50000000, 200000000, 400000000
	};
	unsigned int base_clk = 0, div;
	unsigned int i, cfg;

	for (i = 0; i < ARRAY_SIZE(emmc_clk); i++) {
		if (clock <= emmc_clk[i]) {
			base_clk = emmc_clk[i];
			break;
		}
	}

	div = base_clk / clock;
	if (base_clk % clock)
		pr_warn("unsopported freq: %d\n", clock);
	set_sys_reg_m(NNP_SYS_APB_REG_BASE, EMMC_CLK_RST_CTRL0,
		i|(div<<24), 0x7f000003);
	#endif
}
EXPORT_SYMBOL(fh_pmu_set_emmc_clock);

void fh_pmu_emmc_reset(void)
{
	#if 0
	_reset_ip_wc(NNP_SYS_APB_REG_BASE, EMMC_CLK_RST_CTRL1,
		EMMC_HOST_SOFT_RST);
	_reset_ip_wc(NNP_SYS_APB_REG_BASE, EMMC_CLK_RST_CTRL1,
		EMMC_PHY_SOFT_RST);
	#endif
}
EXPORT_SYMBOL(fh_pmu_emmc_reset);

void fh_pmu_set_emmc_sample_delay0(unsigned int val)
{
	#if 0
	set_sys_reg_m(NNP_SYS_APB_REG_BASE, EMMC_CARD_PAD_SEL,
		val << 5, 7 << 5);
	#endif
}
EXPORT_SYMBOL(fh_pmu_set_emmc_sample_delay0);

void fh_pmu_set_emmc_sample_delay1(unsigned int val)
{
	#if 0
	set_sys_reg_m(NNP_SYS_APB_REG_BASE, EMMC_CARD_PAD_SEL,
		val << 8, 7 << 8);
	#endif
}
EXPORT_SYMBOL(fh_pmu_set_emmc_sample_delay1);

void fh_pmu_set_dma_sel_low(unsigned int val)
{
	//set_sys_reg(CPU_SYS_APB_REG_BASE, REG_DMA_SEL_LOW, val);
}
EXPORT_SYMBOL(fh_pmu_set_dma_sel_low);

void fh_pmu_set_dma_sel_high(unsigned int val)
{
	//set_sys_reg(CPU_SYS_APB_REG_BASE, REG_DMA_SEL_HIGH, val);
}
EXPORT_SYMBOL(fh_pmu_set_dma_sel_high);

void fh_pmu_set_dma0_axcache(unsigned int val)
{
	//set_sys_reg(CPU_SYS_APB_REG_BASE, REG_DMA0_AXCACHE, val);
}
EXPORT_SYMBOL(fh_pmu_set_dma0_axcache);

void fh_pmu_set_dma1_axcache(unsigned int val)
{
	//set_sys_reg(CPU_SYS_APB_REG_BASE, REG_DMA1_AXCACHE, val);
}
EXPORT_SYMBOL(fh_pmu_set_dma1_axcache);

void mol_pmu_set_efuse_lock_blk(unsigned int val)
{
	//set_sys_reg(VDU_SYS_APB_REG_BASE, REG_EFUSE_CTRL_16, val);
}
EXPORT_SYMBOL(mol_pmu_set_efuse_lock_blk);

void fh_pmu_spi_slave_enable(unsigned int enable)
{
	//set_sys_reg(TOP_SYS_APB_REG_BASE, REG_SPI0_MODE, enable);
}
EXPORT_SYMBOL(fh_pmu_spi_slave_enable);

void fh_pmu_usb_axi_clk_en(unsigned int enable)
{
#ifdef CONFIG_USB_DWC3_U2_ONLY
	set_sys_reg_m(NNP_SYS_APB_REG_BASE, USB2_CLK_RST_CTRL,
		enable, 1<<0);
#else
	set_sys_reg_m(NNP_SYS_APB_REG_BASE, USB3_CLK_RST_CTRL,
		enable, 1<<0);
#endif
}
EXPORT_SYMBOL(fh_pmu_usb_axi_clk_en);
#endif

void fh_pmu_dwi2s_set_clk(unsigned int div_i2s, unsigned int div_mclk)
{
	unsigned int reg;

	reg = fh_pmu_get_reg(PMU_DWI2S_CLK_DIV_REG);
	reg &= ~(0xfff << PMU_DWI2S_CLK_DIV_SHIFT);
	reg |= ((div_i2s-1) << 6 | (div_mclk-1)) << PMU_DWI2S_CLK_DIV_SHIFT;
	fh_pmu_set_reg(PMU_DWI2S_CLK_DIV_REG, reg);

	/* i2s_clk switch to PLLVCO */
	reg = fh_pmu_get_reg(PMU_DWI2S_CLK_SEL_REG);
	reg &= ~(1 << PMU_DWI2S_CLK_SEL_SHIFT);
	reg |= 1 << PMU_DWI2S_CLK_SEL_SHIFT;
	fh_pmu_set_reg(PMU_DWI2S_CLK_SEL_REG, reg);
}
EXPORT_SYMBOL_GPL(fh_pmu_dwi2s_set_clk);


int ephy_pass_reset(void)
{
	int ret;

	ret = fh_pmu_get_reg(REG_PMU_RESERVED2);

	if (ret & (1 << EPHY_PASS_CHECK_BIT_POS))
		return 1;

	return 0;

}
EXPORT_SYMBOL_GPL(ephy_pass_reset);


#define REFIX_TRAIN_DATA_OFFSET	(0)
#define MIN_TRAINING_DATA	-8
#define MAX_TRAINING_DATA	7
int __refix_train_data(int *pdata, int offset)
{
	int temp_data;

	temp_data = *pdata;
	temp_data &= INSIDE_PHY_TRAINING_MASK;

	if (temp_data & 0x08)
		temp_data  = (~INSIDE_PHY_TRAINING_MASK) | temp_data;

	temp_data += offset;

	if (temp_data < MIN_TRAINING_DATA || temp_data > MAX_TRAINING_DATA) {
		pr_err("cal data [%d] should limit in [%d , %d]\n",
		temp_data, MIN_TRAINING_DATA, MAX_TRAINING_DATA);
		return -1;
	}
	temp_data &= INSIDE_PHY_TRAINING_MASK;

	*pdata = temp_data;
	return 0;
}

void refix_train_data(int *pdata)
{
	__refix_train_data(pdata, REFIX_TRAIN_DATA_OFFSET);
}



void fh_pmu_internal_ephy_reset(void)
{
	int train_data;
	/*reset sunplus phy */
	/*
	 * ephy shutdown: ---____________________________
	 * ephy rst         : ___|<=L_10ms=>|--|<=H_12us=>|--
	 * ephy clkin       : _-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
	 */
	/* pull up shut down first.. */
	fh_pmu_set_reg_m(REG_PMU_ETHPHY_REG0,
	1 << INSIDE_PHY_SHUTDOWN_BIT_POS,
	1 << INSIDE_PHY_SHUTDOWN_BIT_POS);

	udelay(5);
	/* pull down shut down and rst for 10ms. */
	fh_pmu_set_reg_m(REG_PMU_ETHPHY_REG0, 0,
	1 << INSIDE_PHY_SHUTDOWN_BIT_POS);

	fh_pmu_set_reg_m(REG_PMU_SWRSTN_NSR, 0,
	1 << INSIDE_PHY_RST_BIT_POS);

	mdelay(10);
	/* pull up rst for 12us. */
	fh_pmu_set_reg_m(REG_PMU_SWRSTN_NSR,
	1 << INSIDE_PHY_RST_BIT_POS,
	1 << INSIDE_PHY_RST_BIT_POS);

	udelay(12);

	train_data = fh_pmu_get_reg(REG_PMU_EPHY_PARAM);
	if (train_data & (1 << TRAINING_EFUSE_ACTIVE_BIT_POS)) {
		/* train_data */
		refix_train_data(&train_data);
		pr_info("ephy: training data is :%x\n",
		train_data);
		fh_pmu_set_reg_m(REG_PMU_ETHPHY_REG0,
		(train_data & INSIDE_PHY_TRAINING_MASK)
		<< INSIDE_PHY_TRAINING_BIT_POS,
		INSIDE_PHY_TRAINING_MASK << INSIDE_PHY_TRAINING_BIT_POS);
	} else{
		/* todo set default value...*/
		train_data = 0;
		pr_info("ephy: no training data, use default:%x\n",
			train_data);
		/* train_data */
		fh_pmu_set_reg_m(REG_PMU_ETHPHY_REG0,
		train_data << INSIDE_PHY_TRAINING_BIT_POS,
		INSIDE_PHY_TRAINING_MASK << INSIDE_PHY_TRAINING_BIT_POS);
	}

}

int fh_pmu_ephy_sel(__u32 phy_sel)
{
	if (ephy_pass_reset())
		return 0;
#if 0
	fh_pmu_set_reg_m(REG_PMU_CLK_SEL,
	1 << CLK_SCAN_BIT_POS, 1 << CLK_SCAN_BIT_POS);
	if (phy_sel == EXTERNAL_PHY) {
		/* close inside phy */
		fh_pmu_set_reg_m(REG_PMU_ETHPHY_REG0,
		0 << INSIDE_PHY_ENABLE_BIT_POS, 1 << INSIDE_PHY_ENABLE_BIT_POS);
		/* gate inside phy */
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1,
		1 << INSIDE_CLK_GATE_BIT_POS,
		1 << INSIDE_CLK_GATE_BIT_POS);
		/* set div */
		fh_pmu_set_reg_m(REG_PMU_CLK_DIV6,
		1 << MAC_REF_CLK_DIV_BIT_POS,
		MAC_REF_CLK_DIV_MASK << MAC_REF_CLK_DIV_BIT_POS);
		/* set pad */
		/* eth ref clk out Ungate */
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE,
		0 << ETH_REF_CLK_OUT_GATE_BIT_POS,
		1 << ETH_REF_CLK_OUT_GATE_BIT_POS);
		/* eth rmii clk Ungate */
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE,
		0 << ETH_RMII_CLK_OUT_GATE_BIT_POS,
		1 << ETH_RMII_CLK_OUT_GATE_BIT_POS);
		/* switch mac clk in */
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL,
		1 << IN_OR_OUT_PHY_SEL_BIT_POS,
		1 << IN_OR_OUT_PHY_SEL_BIT_POS);
	} else {
		/* inside phy enable */
		fh_pmu_set_reg_m(REG_PMU_ETHPHY_REG0,
		1 << INSIDE_PHY_ENABLE_BIT_POS,
		1 << INSIDE_PHY_ENABLE_BIT_POS);
		/* set pad no need */
		/* eth ref clk out gate */
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE,
		1 << ETH_REF_CLK_OUT_GATE_BIT_POS,
		1 << ETH_REF_CLK_OUT_GATE_BIT_POS);
		/* eth rmii clk gate */
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE,
		1 << ETH_RMII_CLK_OUT_GATE_BIT_POS,
		1 << ETH_RMII_CLK_OUT_GATE_BIT_POS);
		/* inside phy clk Ungate */
		fh_pmu_set_reg_m(REG_PMU_CLK_GATE1,
		0 << INSIDE_CLK_GATE_BIT_POS,
		1 << INSIDE_CLK_GATE_BIT_POS);
		/* int rmii refclk mux */
		fh_pmu_set_reg_m(REG_PMU_CLK_SEL,
		0 << IN_OR_OUT_PHY_SEL_BIT_POS,
		1 << IN_OR_OUT_PHY_SEL_BIT_POS);
	}
#endif
	return 0;
}

int fh_pmu_eth_set_speed(unsigned int speed)
{
#if 0
	unsigned int reg;

	reg = fh_pmu_get_reg(PMU_RMII_SPEED_MODE);
	if (speed == 10)
		reg &= ~(FH_GMAC_SPEED_100M);
	else if (speed == 100)
		reg |= FH_GMAC_SPEED_100M;
	else{
		pr_err("ERROR: wrong param for emac set speed, %d\n",
		speed);
		return -1;
	}

	fh_pmu_set_reg(PMU_RMII_SPEED_MODE, reg);
#endif
	return 0;
}

void fh_pmu_eth_reset(void)
{
	//_pmu_ahb_reset(~(1 << EMAC_HRSTN_BIT), 1000, 1);
}

void fh_pmu_wdt_pause(void)
{
	unsigned int reg;

	reg = fh_pmu_get_reg(REG_PMU_WDT_CTRL);
	reg |= 0x100;
	fh_pmu_set_reg(REG_PMU_WDT_CTRL, reg);
}
EXPORT_SYMBOL_GPL(fh_pmu_wdt_pause);

void fh_pmu_wdt_resume(void)
{
	unsigned int reg;

	reg = fh_pmu_get_reg(REG_PMU_WDT_CTRL);
	reg &= ~(0x100);
	fh_pmu_set_reg(REG_PMU_WDT_CTRL, reg);
}
EXPORT_SYMBOL_GPL(fh_pmu_wdt_resume);

void fh_pmu_usb_utmi_rst(void)
{
	unsigned int pmu_reg;

	pmu_reg = fh_pmu_get_reg(REG_PMU_NN_SWRST_CTRL);
	pmu_reg &= ~(USB_UTMI_RST_BIT);
	fh_pmu_set_reg(REG_PMU_NN_SWRST_CTRL, pmu_reg);
	mdelay(1);
	pmu_reg = fh_pmu_get_reg(REG_PMU_NN_SWRST_CTRL);
	pmu_reg |= USB_UTMI_RST_BIT;
	fh_pmu_set_reg(REG_PMU_NN_SWRST_CTRL, pmu_reg);
	msleep(20);
}
EXPORT_SYMBOL_GPL(fh_pmu_usb_utmi_rst);

void fh_pmu_usb_phy_rst(void)
{
	unsigned int pmu_reg;

	pmu_reg = fh_pmu_get_reg(REG_PMU_USB_SYS1);
	pmu_reg &= (~USB_IDDQ_PWR_BIT);
	fh_pmu_set_reg(REG_PMU_USB_SYS1, pmu_reg);
	mdelay(1);
	pmu_reg = fh_pmu_get_reg(REG_PMU_USB_SYS0);
	pmu_reg |= (USB_PHY_RST_BIT);
	fh_pmu_set_reg(REG_PMU_USB_SYS0, pmu_reg);
	mdelay(1);
	pmu_reg = fh_pmu_get_reg(REG_PMU_USB_SYS0);
	pmu_reg &= (~USB_PHY_RST_BIT);
	fh_pmu_set_reg(REG_PMU_USB_SYS0, pmu_reg);
}
EXPORT_SYMBOL_GPL(fh_pmu_usb_phy_rst);

void fh_pmu_usb_resume(void)
{
	unsigned int pmu_reg;

	pmu_reg = fh_pmu_get_reg(REG_PMU_USB_SYS0);
	pmu_reg |= (USB_SLEEP_MODE_BIT);
	fh_pmu_set_reg(REG_PMU_USB_SYS0, pmu_reg);
	mdelay(1);
}
EXPORT_SYMBOL_GPL(fh_pmu_usb_resume);

void fh_pmu_usb_tune(void)
{
	fh_pmu_set_reg(REG_PMU_USB_TUNE, USB_TUNE_ADJ_SET);
}
EXPORT_SYMBOL_GPL(fh_pmu_usb_tune);

void fh_pmu_usb_vbus_vldext(void)
{
	unsigned int pmu_reg;

	pmu_reg = fh_pmu_get_reg(REG_PMU_USB_CFG);
	pmu_reg |= (0x1 << 4);	/* BIT4: VBUSVLDEXT */
	pmu_reg |= (0x1 << 8);	/* BIT8: VBUSVLDEXTSEL */
	fh_pmu_set_reg(REG_PMU_USB_CFG, pmu_reg);
}
EXPORT_SYMBOL_GPL(fh_pmu_usb_vbus_vldext);

void _pmu_ahb_reset(unsigned int reg, unsigned int retry, unsigned int udelay)
{
	fh_pmu_set_reg(REG_PMU_SWRST_AHB_CTRL, reg);

	while (fh_pmu_get_reg(REG_PMU_SWRST_AHB_CTRL) != 0xffffffff) {
		if (retry-- <= 0)
			return;

		udelay(udelay);
	}
}

void fh_pmu_sdc_reset(int slot_id)
{
#ifndef CONFIG_ARCH_FH8862
	unsigned int reg = 0;

	if (slot_id == 1)
		reg = ~(1 << SDC1_HRSTN_BIT);
	else if (slot_id == 0)
		reg = ~(1 << SDC0_HRSTN_BIT);
	else
		reg = 0;

	_pmu_ahb_reset(reg, 1000, 1);
#endif
}
EXPORT_SYMBOL_GPL(fh_pmu_sdc_reset);

void fh_pmu_restart(void)
{
	fh_pmu_set_reg(REG_PMU_SWRST_MAIN_CTRL0, 0x7fffffff);
}

void fh_pmu_arxc_write_A625_INT_RAWSTAT(unsigned int val)
{
	fh_pmu_set_reg(PMU_A625_INT_RAWSTAT, val);
}
EXPORT_SYMBOL_GPL(fh_pmu_arxc_write_A625_INT_RAWSTAT);

unsigned int fh_pmu_arxc_read_ARM_INT_RAWSTAT(void)
{
	return fh_pmu_get_reg(PMU_ARM_INT_RAWSTAT);
}
EXPORT_SYMBOL_GPL(fh_pmu_arxc_read_ARM_INT_RAWSTAT);

void fh_pmu_arxc_write_ARM_INT_RAWSTAT(unsigned int val)
{
	fh_pmu_set_reg(PMU_ARM_INT_RAWSTAT, val);
}
EXPORT_SYMBOL_GPL(fh_pmu_arxc_write_ARM_INT_RAWSTAT);

unsigned int fh_pmu_arxc_read_ARM_INT_STAT(void)
{
	return fh_pmu_get_reg(PMU_ARM_INT_STAT);
}
EXPORT_SYMBOL_GPL(fh_pmu_arxc_read_ARM_INT_STAT);

void fh_pmu_arxc_reset(unsigned long phy_addr)
{
	unsigned int arc_addr;

	/*ARC Reset*/
	fh_pmu_set_reg(REG_PMU_CPU_SWRSTN_NSR, ~(1<<ARC_RSTN_BIT));

	arc_addr = ((phy_addr & 0xffff) << 16) | (phy_addr >> 16);

	fh_pmu_set_reg(REG_PMU_A625BOOT0, 0x7940266B);
	/* Configure ARC Bootcode start address */
	fh_pmu_set_reg(REG_PMU_A625BOOT1, arc_addr);
	fh_pmu_set_reg(REG_PMU_A625BOOT2, 0x0F802020);
	fh_pmu_set_reg(REG_PMU_A625BOOT3, arc_addr);

	/*clear ARC ready flag*/
	fh_pmu_arxc_write_ARM_INT_RAWSTAT(0);

	/* don't let ARC run when release ARC */
	fh_pmu_set_reg(REG_PMU_A625_START_CTRL, 0);
	udelay(2);

	/* ARC reset released */
	fh_pmu_set_reg(REG_PMU_CPU_SWRSTN_NSR, 0xFFFFFFFF);
}
EXPORT_SYMBOL_GPL(fh_pmu_arxc_reset);

void fh_pmu_set_hashen(unsigned long en)
{

	unsigned int val;

	val = fh_pmu_get_reg(REG_PMU_DMA_HDSHAKE_EN);
	if (en)
		val |= 1<<16;
	else
		val &= ~(1<<16);

	fh_pmu_set_reg(REG_PMU_DMA_HDSHAKE_EN, val);

}
EXPORT_SYMBOL_GPL(fh_pmu_set_hashen);

void fh_pmu_set_stmautostopgpio(int stmid, int gpio)
{
	unsigned int val;

	val = fh_pmu_get_reg(REG_PMU_ETHPHY_REG0);

	if (stmid) {
		val &= (~0xfc00);
		val |= gpio<<10;
	} else {
		val &= (~0x3f0);
		val |= gpio<<4;
	}
	fh_pmu_set_reg(REG_PMU_ETHPHY_REG0, val);
}
EXPORT_SYMBOL_GPL(fh_pmu_set_stmautostopgpio);

void fh_pmu_arxc_kickoff(void)
{
	//start ARC625
	fh_pmu_set_reg(REG_PMU_A625_START_CTRL, 0x10);
}
EXPORT_SYMBOL_GPL(fh_pmu_arxc_kickoff);

int fh_pmu_init(void)
{
	spin_lock_init(&scu_lock);

	return 0;
}

void fh_pmu_set_sdc1_funcsel(unsigned int val)
{
#ifdef SD1_FUNC_SEL_MAP
	static int sd1_func_map[] = SD1_FUNC_SEL_MAP; /* func sel map */

	BUG_ON(val >= ARRAY_SIZE(sd1_func_map));
#if defined(CONFIG_ARCH_FH8862) || defined(CONFIG_ARCH_FH8866)
	fh_pmu_set_reg_m(REG_PMU_SDC_MISC, sd1_func_map[val] << 30, 0xc0000000);
#else
	fh_pmu_set_reg(REG_PMU_SD1_FUNC_SEL, sd1_func_map[val]);
#endif
#endif
}
EXPORT_SYMBOL_GPL(fh_pmu_set_sdc1_funcsel);

unsigned int fh_pmu_get_tsensor_init_data(void)
{
#ifdef REG_PMU_RTC_PARAM
	return fh_pmu_get_reg(REG_PMU_RTC_PARAM);
#else
	return 0;
#endif
}
EXPORT_SYMBOL_GPL(fh_pmu_get_tsensor_init_data);
